package org.maxgroundstation.simulation.service.list;

import java.util.Iterator;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.maxgroundstation.simulation.service.Service;
import org.maxgroundstation.simulation.service.ServiceCommunication;
import org.maxgroundstation.simulation.service.ServiceDataFrame;
import org.maxgroundstation.simulation.service.ServiceUtil;

/**
 * The list service.
 */
public class ListService extends Service {

	// Static members
	public static final String SERVICE_ID = ServiceUtil.getServiceID("__list");
	private static final String LIST_CMD = "list";
	private static final String SUBSCRIBE_CMD = "start=";
	private static final String UNSUBSCRIBE_CMD = "stop=";
	
	/**
	 * Constructor
	 * @param comm the service communication.
	 */
	public ListService(ServiceCommunication comm) {
		// Use Service constructor.
		super(comm);
		
		name = "List";
		description = "Returns XML list of available services on robot.";
	}

	@Override
	public String getID() {
		return SERVICE_ID;
	}
	
	@Override
	public boolean isDefaultService() {
		return true;
	}

	@Override
	public void handleResponse(ServiceDataFrame dataFrame, int commType)
			throws Exception {
		
		String dataString = dataFrame.getDataString().trim();
		
		// Check if request for list of services, subscribing or unsubscribing to a service.
		if (LIST_CMD.equals(dataString)) {
		
			// Create DOM document with list of all available services.
			Document outputDoc = new Document();
			Element serviceListElement = new Element("service-list");
			outputDoc.addContent(serviceListElement);
			outputDoc.setRootElement(serviceListElement);
			
			Iterator<Service> i = comm.getServices().iterator();
			while (i.hasNext()) {
				Service service = i.next();
				Element serviceElement = new Element("service");
				serviceListElement.addContent(serviceElement);
				serviceElement.setAttribute("id", service.getID().trim());
				serviceElement.setAttribute("name", service.getName());
				serviceElement.setAttribute("format", service.getFormat());
				serviceElement.setAttribute("description", service.getDescription());
				
				Iterator<String> j = service.getParameters().keySet().iterator();
				while (j.hasNext()) {
					String parameter = j.next();
					String value = service.getParameters().get(parameter);
					Element paramElement = new Element("param");
					paramElement.setAttribute("key", parameter);
					paramElement.setAttribute("value", value);
					serviceElement.addContent(paramElement);
				}
			}
		
			// Create XML string from DOM document.
			XMLOutputter fmt = new XMLOutputter();
			fmt.setFormat(Format.getCompactFormat());
			String xmlString = fmt.outputString(outputDoc);
			
			comm.log("List server sending list XML string to client: '" + xmlString + "'");
			
			// Respond with XML list of services..
			comm.sendServicePost(commType, getID(), dataFrame.getClientID(), xmlString.getBytes());
		}
		else if (dataString.startsWith(SUBSCRIBE_CMD)) {
			String subscriptionServiceID = dataString.substring(SUBSCRIBE_CMD.length()).trim();
			comm.log("Attempting to subscribe to " + subscriptionServiceID);
			Service subscribeService = comm.getService(subscriptionServiceID);
			if (subscribeService.isSubscribable()) 
				subscribeService.subscribe(dataFrame.getClientID(), commType);
			else comm.log("Service: " + subscriptionServiceID + " is not subscribable");
		}
		else if (dataString.startsWith(UNSUBSCRIBE_CMD)) {
			String subscriptionServiceID = dataString.substring(UNSUBSCRIBE_CMD.length()).trim();
			comm.log("Attempting to unsubscribe to " + subscriptionServiceID);
			Service subscribeService = comm.getService(subscriptionServiceID);
			if (subscribeService.isSubscribable()) 
				subscribeService.unsubscribe(dataFrame.getClientID());
			else comm.log("Service: " + subscriptionServiceID + " is not subscribable");
		}
		else comm.log("Not recognized list command: " + dataString);
	}

	@Override
	public void shutDown() {
		// Do nothing.
	}
	
	@Override
	public boolean isSubscribable() {
		return false;
	}
}